﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WF_Xtension
{
	/// <summary>
	/// Creates a Euclidean geometrical 2-dimensional vector
	/// </summary>
	public struct Vector
	{
		const float PI = (float)Math.PI;//Preform a cast only once for code optimization

		#region Variables
		float x, y, magnitude;
		#endregion

		/// <summary>
		/// Creates a Euclidean geometrical 2-dimensional vector
		/// </summary>
		/// <param name="x">Magnitude of X aspect of vector</param>
		/// <param name="x">Magnitude of Y aspect of vector</param>
		public Vector(float x, float y)
		{
			this.x = x;
			this.y = y;
			magnitude = -1;
		}

		#region Methods
		/// <summary>
		/// Normalizes the vector to a unit vector
		/// and stores it as the current vector
		/// </summary>
		public void NormalizeInPlace()
		{
			x /= Magnitude;
			y /= Magnitude;
		}

		/// <summary>
		/// Normalizes the vector to a unit vector
		/// </summary>
		/// <returns>Normalized unit vector</returns>
		public Vector Normalize()
		{
			return new Vector(x /= Magnitude, y /= Magnitude);
		}

		/// <summary>
		/// Returns the x and y directions of this instance
		/// </summary>
		public override string ToString()
		{
			return "{" + x + ", " + y + "}";
		}
		#endregion

		#region Accessors
		/// <summary>
		/// Calculates and returns the angle of the vector, in degrees
		/// </summary>
		public float AngleInDegrees { get { return (float)Math.Atan(y / x) * 180 / PI; } }

		/// <summary>
		/// Calculates and returns the angle of the vector, in radians
		/// </summary>
		public float AngleInRadians { get { return (float)Math.Atan(y / x); } }

		/// <summary>
		/// Gets or sets X aspect of vector
		/// </summary>
		public float X
		{
			get { return x; }
			set
			{
				x = value;
				magnitude = -1;
			}
		}
		/// <summary>
		/// Gets or sets Y aspect of vector
		/// </summary>
		public float Y
		{
			get { return y; }
			set
			{
				y = value;
				magnitude = -1;
			}
		}
		/// <summary>
		/// Gets the magnitude of the vector
		/// </summary>
		public float Magnitude
		{
			get
			{
				if (magnitude < 0)
					magnitude = (float)Math.Sqrt(X * X + Y * Y);
				return magnitude;
			}
		}
		#endregion

		#region PredefinedVectors
		public static readonly Vector
			Zero = new Vector(0, 0),
			Left = new Vector(-1, 0),
			Right = new Vector(1, 0),
			Up = new Vector(-1, 0),
			Down = new Vector(1, 0);
		#endregion

		#region OperatorOverloading
		public static Vector operator+(Vector lhs, Vector rhs)
		{
			return new Vector(lhs.x + rhs.x, lhs.y + rhs.y);
		}
		public static Vector operator-(Vector lhs, Vector rhs)
		{
			return new Vector(lhs.x - rhs.x, lhs.y - rhs.y);
		}
		public static Vector operator*(Vector lhs, float rhs)
		{
			return new Vector(lhs.x * rhs, lhs.y * rhs);
		}
		public static float operator*(Vector lhs, Vector rhs)
		{
			return lhs.x * rhs.x + lhs.y * rhs.y;
		}
		public static Vector operator /(Vector lhs, float rhs)
		{
			return new Vector(lhs.x / rhs, lhs.y / rhs);
		}
		#endregion
	}
}
